#pragma once

#include <list>
#include "math.h"
#include "WorldLink.h"
#include "GeometricDefinitions.h"
#include "CollisionDetection.h"
#include "../engine/Unit.h"
#include "../engine/Bullet.h"
namespace Putin{

#define M_PI       3.14159265358979323846
#define DynamicType 1
#define StaticType 2
#define ProjectileType 3

/*
 * Forward declarations
 */
struct DynamicObjectConstants;
struct ProjectileObjectConstants;
class DynamicPhysicsObject;
class StaticPhysicsObject;
class ProjectilePhysicsObject;


/*
 * Class that handles updates of all objects and calls collision detection
 */

class PhysicsHandler
{
public:
	PhysicsHandler(WorldLink* worldlink);
	~PhysicsHandler(void);

	virtual void AddDynamicObject(Unit * unit,int unit_nr);
	virtual void RemoveDynamicObject(int unit_nr);
	virtual void AddStaticObject(GameObject* gameobject, int obj_nr);
	virtual void RemoveStaticObject(int obj_nr);
	virtual void AddProjectileObject(Bullet* bullet);
	virtual void Update();


	CollisionDetection* mCollisionDetection;		//Broad phase collision detection
	WorldLink* mWorldLink;							//Communicates with terrain/scenemanager
	std::map<int, DynamicPhysicsObject*> mDynamicObjectMap;//Holds pointers to all units
	std::map<int, StaticPhysicsObject*> mStaticObjectMap;	//Holds pointers to all static objects
	std::list<ProjectilePhysicsObject*> mProjectileObjectList;			//Holds pointers to all projectiles
	bool mCollisionsOn;


	//Pointer to a method with a rayscene querry set up to the world that checks height
	//Pointer to a method with a rayscene querry set up to the world that checks normal
};


struct DynamicObjectConstants
{
	float fov;					//Field of view		-	Radians (0-pi) - halts acceleration until target within fov
	float turningSpeed;			//Turning speed		-	Larger than zero
	float tracktion;			//0 < tracktion < 1	-	0 = ice, 1 = perfect tracktion
	float maxSpeed;				//Maximum speed		-	Larger than zero
	float turningSmoothener;	//Turningsmoothener	-	Radians (0-pi), clamps the turning speed to "turningSpeed" until within interval
	float acceleration;			//Acceleration		-	Smaller is faster (don't set it to too fast ;))
	float maxTorque;			//Should be set to maxSpeed*tracktion
	float weight;
	bool accelerationType;		//false = full throttle when target in fov, true = smoother
};



class PhysicsObject
{
public:
	int mType;
};


class DynamicPhysicsObject: public PhysicsObject
{
public:
	DynamicPhysicsObject(Unit* unit,WorldLink* worldlink);
	virtual ~DynamicPhysicsObject();
	virtual void UpdatePrimary(void);
	virtual void UpdateSecondary(void);

private:
	virtual void UpdateControl(void);

	virtual void CreateGeometry();

public:
	Geometry *mGeometry;
	Vec3f mPosition;
	Vec3f mPositionOld;
	Vec3f mSpeed;
	Vec3f mNormal;
	Vec3f mDirection;
	Vec3f mDirectionOld;
	DynamicObjectConstants * mConstants;
	Unit* mUnit;
	float mOffset;
private:
	float mTorque;

	Vec3f mWaypoint;

	WorldLink* mWorldLink;
};

class StaticPhysicsObject: public PhysicsObject
{
public:
	StaticPhysicsObject(GameObject* gameobject);
	virtual	~StaticPhysicsObject();
	Geometry *mGeometry;
};


struct ProjectileObjectConstants
{
	float initialAngle;			//Range: 0-pi/2 (But it shouldnt really be set to larger than 70deg)			
	float gravity;				//Dunno, trial and error
	float speed;				//1 = realtime, 1.5 = 50% faster
	float splashRange;			//units splashrange
};

class ProjectilePhysicsObject: public PhysicsObject
{
public:
	ProjectilePhysicsObject(Bullet * bullet, CollisionDetection* cd);
	virtual ~ProjectilePhysicsObject();
	virtual void Update(void);

public:
	Geometry *mGeometry;
	Vec3f mPosition;
	Vec3f mStartPosition;
	ProjectileObjectConstants* mPoc;
	Bullet * mBullet;
	bool mIsDesposed;
	Vec3f mTarget;
private:
	//ProjectileObjectConstants * mConstants;
	CollisionDetection* mCollisionDetection; 
	float t;
	float t_final;
	Vec3f mDirection;
	float mInitialAngle;
};


}//End namespace Putin
